package com.netty.esc.service.isolate.impl;

import com.netty.esc.common.base.DouFunction;
import com.netty.esc.common.enums.UserImKeyEnum;
import com.netty.esc.dao.repository.UserRepository;
import com.netty.esc.entity.model.FriendsOnlineDTO;
import com.netty.esc.entity.neo4j.node.PersonEntity;
import com.netty.esc.service.isolate.CommonFriendService;
import com.netty.esc.service.active.FriendsActiveAction;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author: ext.zhaoyang17
 * @date: 2022.11.04
 * 公共好友的业务类
 */
@Service
public class CommonFriendServiceImpl implements CommonFriendService {

    @Resource
    FriendsActiveAction friendsActiveAction;
    @Resource
    UserRepository userRepository;

    @Resource
    RedisTemplate<String,Object> redisTemplate;

    private final DouFunction<List<Long>,List<Object>,List<FriendsOnlineDTO>> friendsOnlineValueHandle = (a, b)->{
        List<FriendsOnlineDTO> res = new ArrayList<>();
        for (int i = 0; i < Math.min(a.size(),b.size()); i++) {
            res.add(FriendsOnlineDTO.builder()
                    .userId(a.get(i))
                    .online((Boolean) b.get(i))
                    .build());
        }return res;
    };

    //redis开启管道进行批量查询,查询在线状态的好友列表
    public Function<List<Long>,List<FriendsOnlineDTO>> findFriendsOnline = relations->{
        List<Object> objects = redisTemplate.executePipelined(new SessionCallback<FriendsOnlineDTO>() {
            @Override
            public <K, V> FriendsOnlineDTO execute(RedisOperations<K, V> operations) throws DataAccessException {
                relations.forEach(e -> ((RedisTemplate<String, Long>) operations).opsForValue().getBit(UserImKeyEnum.ESC_IM_ONLINE.getKey(), e));
                return null;
            }
        });
        return friendsOnlineValueHandle.apply(relations,objects);

    };


    @Override
    public void assentFinishSendMessage(Long userId) {
        friendsActiveAction.friendRequest(userId);
    }

    @Override
    public void assentFriendOnline(Long userId) {
        //查找用户的好友
        List<Long> longs = userRepository.findFriendRelation(userId)
                .map(e -> e.stream().map(PersonEntity::getId).collect(Collectors.toList()))
                .orElse(new ArrayList<>());
        if (longs.isEmpty()){
            return;
        }
        friendsActiveAction.assentFriendOnline(
                findFriendsOnline.apply(longs).stream()
                        .filter(FriendsOnlineDTO::getOnline)
                        .map(FriendsOnlineDTO::getUserId)
                        .collect(Collectors.toList()));
    }

    @Override
    public void assentFriendDown(Long userId) {
        List<Long> longs = userRepository.findFriendRelation(userId)
                .map(e -> e.stream().map(PersonEntity::getId).collect(Collectors.toList()))
                .orElse(new ArrayList<>());
        if (longs.isEmpty()){
            return;
        }
        friendsActiveAction.assentFriendDown(
                findFriendsOnline.apply(longs).stream()
                        .filter(FriendsOnlineDTO::getOnline)
                        .map(FriendsOnlineDTO::getUserId)
                        .collect(Collectors.toList()));
    }


    @Override
    public void offOlineMessageSave(Long userId, Long sendUserId, Date time) {
        Date date = Optional.ofNullable((Date) redisTemplate.opsForHash().get(UserImKeyEnum.ESC_IM_OFF_ONLINE_MESSAGE.getKey() + ":" + userId, sendUserId.toString())).orElse(new Date());
        redisTemplate.opsForHash().put(UserImKeyEnum.ESC_IM_OFF_ONLINE_MESSAGE.getKey()+":"+userId,sendUserId.toString(),date);
        redisTemplate.expire(UserImKeyEnum.ESC_IM_OFF_ONLINE_MESSAGE.getKey()+":"+userId,30, TimeUnit.DAYS);
    }


}
